package com.ideal.frame.node.netty;

import com.ideal.frame.node.entity.NodeTb;
import com.ideal.frame.node.netty.server.NettyServerInitializer;
import com.ideal.frame.node.service.NodeService;
import io.netty.bootstrap.ServerBootstrap;
import io.netty.channel.ChannelFuture;
import io.netty.channel.ChannelOption;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.nio.NioEventLoopGroup;
import io.netty.channel.socket.nio.NioServerSocketChannel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

/**
 * @description:
 * @author: xuyang
 * @date: 2021/9/2 9:33
 */
@Component
@Slf4j
//@ConditionalOnExpression("#{nodeService.canBeNettyServer()}")
public class NettyServer {
    /**
     * NioEventLoopGroup是一个处理I / O操作的多线程事件循环。 Netty为不同类型的传输提供各种EventLoopGroup实现。
     * 我们在此示例中实现了服务器端应用程序，因此将使用两个NioEventLoopGroup。第一个，通常称为“老板”，接受传入连接。第二个，通常称为“工人”，
     * 一旦老板接受连接并将接受的连接注册到工作人员，就处理被接受连接的流量。使用了多少个线程以及它们如何映射到创建的Channels取决于EventLoopGroup实现，甚至可以通过构造函数进行配置。
     */
    private EventLoopGroup boss = new NioEventLoopGroup();
    private EventLoopGroup work = new NioEventLoopGroup();

    ServerBootstrap bootstrap = null;

    @Autowired
    NettyServerInitializer nettyServerInitializer;

    @Autowired
    NodeService nodeService;

//    /**
//     * 构造器在@PostConstructor前执行
//     */
//    private Pair<String, Integer> pair = null;
//
//    public NettyServer(NodeService nodeService) {
//        NodeTb node = nodeService.getByLevel();
//        // 叶子节点，不需要创建netty服务端
//        if(NodeLevel.ROOT.getValue() == node.getNodelevel()){
//            pair = null;
//        }
//        // 虚拟节点, 不需要创建netty服务端
//        if(NodeType.VIRTUAL_NODE.getValue() == node.getNodetype()){
//            pair = null;
//        }
//        pair = Pair.of(node.getNodeip(), node.getNodeport());
//    }



    /**
     * 启动 Netty
     *
     * @return
     * @throws InterruptedException
     */
    @PostConstruct
    public void start() throws InterruptedException {
//        if(pair == null){
//            log.info("根节点或是虚拟节点，不需要创建netty-server");
//            return;
//        }
//        String host = pair.getLeft();
//        Integer port = pair.getRight();
        NodeTb node = nodeService.getByLevel();

        bootstrap = new ServerBootstrap()
                .group(boss, work)
                .channel(NioServerSocketChannel.class)
                //保持长连接
                .childOption(ChannelOption.SO_KEEPALIVE, true)
                .childHandler(nettyServerInitializer);
        this.doBind(node.getNettyport());
    }

    public void doBind(int port) throws InterruptedException {
        //绑定并开始接受传入的连接。
        log.info("**####端口号port = {}", port);
        ChannelFuture future = bootstrap.bind(port).sync();
        if (future.isSuccess()) {
            log.info("启动 Netty-server 成功");
        }
    }

    /**
     * 销毁
     */
    @PreDestroy
    public void destroy() {
        boss.shutdownGracefully().syncUninterruptibly();
        work.shutdownGracefully().syncUninterruptibly();
        log.info("关闭 Netty-server 成功");
    }
}
